{
module ExprSyntax where
import ExprTokens
import ExprDataTypes
}

%name exprSint
%tokentype { Token }

-- El parser sera de tipo [Token] -> ExpA, y el punto de entrada sera expr pues es la primera regla de produccion.

-- Aqui esta la definicion que le indica al happy como se referencian a cada uno de los tokens en las reglas de producciï¿½n

%token

-- Notese que todos los tokens tiene 1 parametro en su defincion de tipo de datos (en ExprTokens) menos el TokenEntero que tiene 2. En todos los casos el primer parametro era la posicion que para el analisis sintactico se ignora.
-- En el TokenEntero sin embargo el segundo parametro tendra el valor en un Int y como sera referenciado en las reglas (por algun $<num>) se debe indicarle con $$ en que parametro esta dicho valor.
	
	num			{ TokenEntero _ $$ }
	pflot		{ TokenPFlotante _ $$ }
	ident		{ TokenId _ $$ }
	lit			{ TokenLiteral _ $$ }
	'+'			{ TokenMas _ }
	'-'			{ TokenMenos _ }
	'*'			{ TokenPor _ }
	'/'			{ TokenDiv _ }
	'='			{ TokenIgual _ }
	'<>'		{ TokenDistinto _ }
	'>'			{ TokenMayor _ }
	'<'			{ TokenMenor _ }
	'>='		{ TokenMayorIgual _ }
	'<='		{ TokenMenorIgual _ }
	':='		{ TokenAsig _ }
	'!'			{ TokenNot _ }
	'&'			{ TokenAnd _ }
	'|'			{ TokenOr _ }
	'('			{ TokenOCurv _ }
	')'			{ TokenCCurv _ }
	';'			{ TokenSemicolon _ }
	'{'			{ TokenPllaveA _ }
	'}'			{ TokenPllaveC _ }
	'bool'		{ TokenTBool _ }
	'int'		{ TokenTInt _ }
	'double'	{ TokenTDouble _ }
	'string'	{ TokenTString _ }
	'repeat'	{ TokenPRrepeat _ }
	'while'		{ TokenPRwhile _ }
	'else'		{ TokenPRelse _ }
	'if'		{ TokenPRif _ }
	'then'		{ TokenPRthen _ }
	'write'		{ TokenPRwrite _ }
	'read'		{ TokenPRread _ }
    'length'	{ TokenPRlength _ }
    'str2int'	{ TokenPRstr2int _ }
	'true'		{ TokenPRtrue _ }
	'false'		{ TokenPRfalse _ } 
	
%left ';'
%right 'write' 'length' 'str2int'
%left 'if' 'while'
%right 'repeat' 'then'
%right 'else'
%nonassoc 'read'
%right ':='
%left '|' '&' 
%left '<' '>' '<=' '>=' '=' '<>'
%right '!'
%left '+' '-'
%left '*' '/'
%%

-- Definicion de las reglas sintacticas de expresiones

C :: { [ComboTuple] }
C : SenExp ';' C						    { [$1] ++ $3 }
    | SenExp 	        				    { [$1] }

B :: { [ComboTuple] }
B : SenExp 			    { [$1] }
    | '{' C '}'		    { $2 }

T :: { String }
T : 'int'			{ "int" }
    | 'bool'		{ "bool" }
    | 'double'		{ "double" }
    | 'string'		{ "string" }

N :: { ComboTuple }
N : num			{(NumInt $1 ,"int")}
    | pflot		{(NumDouble $1 ,"double")}

SenExp :: { ComboTuple }
SenExp : ident ':=' SenExp 	    				{(Asignacion $1 $3,"") }
	| 'read'             				        {(Read ,"")}
	| 'write' ident       				        {(Write $2 ,"")}
	| 'length' ident       					    {(Length $2 ,"")}
	| T ident       					        {(Declaracion $1 $2 NoExp,"")}
	| T ident ':=' SenExp    				    {(Declaracion $1 $2 (EOpc $4) ,"")}
    | 'if' SenExp 'then' B 	    			    {(Condicional $2 $4 NoBloque,"")}
    | 'if' SenExp 'then' B 'else' B 			{(Condicional $2 $4 (BElse $6) ,"")}
    | 'while' SenExp 'repeat' B 			    {(Iteracion $2 $4 NoBloque,"")}
    | 'while' SenExp 'repeat' B 'else' B	    {(Iteracion $2 $4 (BElse $6) ,"")}
    | SenExp '+' SenExp			                {(Mas $1 $3 ,"")}
 	| SenExp '-' SenExp		                    {(Menos $1 $3 ,"")}
    | SenExp '*' SenExp	                        {(Por $1 $3 ,"")}
    | SenExp '/' SenExp	                        {(Div $1 $3 ,"")}
    | SenExp '=' SenExp	                        {(Igual $1 $3 ,"")}
    | SenExp '<>' SenExp	                    {(Distinto $1 $3 ,"")}
    | SenExp '<' SenExp	                        {(Menor $1 $3 ,"")}
    | SenExp '>' SenExp	                        {(Mayor $1 $3 ,"")}
    | SenExp '<=' SenExp	                    {(MenorIgual $1 $3 ,"")}
    | SenExp '>=' SenExp	                    {(MayorIgual $1 $3 ,"")}
    | '(' SenExp ')'	                        {(Parentesis $2 ,"")}
    | '!' SenExp                                {(ONot $2 ,"")}
    | SenExp '&' SenExp	                        {(OAnd $1 $3 ,"")}
    | SenExp '|' SenExp	                        {(OOr $1 $3 ,"")}
    | ident		                                {(Id $1 ,"")}
    | N			                                { $1 }
    | 'true'	                                {(BTrue ,"bool")}
    | 'false'	                                {(BFalse ,"bool")}
    | lit                                       {(Lit $1 ,"string")}


{

-- El tratamiento de errores es trivial: al primer error, se aborta mostrando la posición del próximo token que queda por ingresar a la pila de análisis.

happyError :: [Token] -> a
happyError [] = error ("Unexpected EOF")
happyError (p:ps) = error ("Parse Error in (Line " ++ show x ++ ", Col " ++ show y ++ ")")
               where (AlexPn _ x y ) = posicion p
}
